using System.Collections.Generic;
using UnityEngine;

namespace Framework.ConditionSystem
{
    public interface ICondition
    {
        public bool Evaluate();
    }

    public readonly struct BoolCondition : ICondition
    {
        public readonly bool Value;
        public BoolCondition(bool value) => Value = value;
        public bool Evaluate() => Value;
    }
    
    public enum CompareMethod { Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual }

    public readonly struct CompareFloatCondition : ICondition
    {
        public readonly float A;
        public readonly float B;
        public readonly CompareMethod Method;

        public CompareFloatCondition(float a, float b, CompareMethod method)
        {
            Method = method;
            A = a;
            B = b;
        }
        
        public bool Evaluate() => Method switch
        {
            CompareMethod.Equal => Mathf.Approximately(A, B),
            CompareMethod.NotEqual => !Mathf.Approximately(A, B),
            CompareMethod.LessThan => A < B,
            CompareMethod.LessThanOrEqual => A <= B,
            CompareMethod.GreaterThan => A > B,
            CompareMethod.GreaterThanOrEqual => A >= B,
            _ => false
        };
    }

    public readonly struct CompareIntCondition : ICondition
    {
        public readonly int A;
        public readonly int B;
        public readonly CompareMethod Method;

        public CompareIntCondition(int a, int b, CompareMethod method)
        {
            Method = method;
            A = a;
            B = b;
        }

        public bool Evaluate() => Method switch
        {
            CompareMethod.Equal => A == B,
            CompareMethod.NotEqual => A != B,
            CompareMethod.LessThan => A < B,
            CompareMethod.LessThanOrEqual => A <= B,
            CompareMethod.GreaterThan => A > B,
            CompareMethod.GreaterThanOrEqual => A >= B,
            _ => false
        };
    }

    public readonly struct NotCondition : ICondition
    {
        public readonly ICondition Condition;
        public NotCondition(ICondition condition) => Condition = condition;
        public bool Evaluate() => !Condition.Evaluate();
    }

    public readonly struct AndCondition : ICondition
    {
        public readonly IEnumerable<ICondition> Conditions;
        public AndCondition(IEnumerable<ICondition> conditions) => Conditions = conditions;
        public AndCondition(params ICondition[] conditions) => Conditions = conditions;

        public bool Evaluate()
        {
            foreach (var condition in Conditions)
                if (!condition.Evaluate()) return false;
            return true;
        }
    }

    public readonly struct OrCondition : ICondition
    {
        public readonly IEnumerable<ICondition> Conditions;
        public OrCondition(IEnumerable<ICondition> conditions) => Conditions = conditions;
        public OrCondition(params ICondition[] conditions) => Conditions = conditions;

        public bool Evaluate()
        {
            foreach (var condition in Conditions)
                if (condition.Evaluate()) return true;
            return false;
        }
    }
}